package protocol;

import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class PairedConnection {

	// ConectionDiscover is the manager
	private ConnectionDiscover manager;

	// Control variables
	private boolean running, readyToUse;

	// Socket and Buffers
	private Socket socket;
	private InputStreamReader input;
	private OutputStreamWriter output;

	// Listener
	private OnNewMessageListener listener;

	//	private LinkedList<String> messagesToSend;

	// Message reciver buffer
	private StringBuffer messageBuffer;

	private final int MAX_MESSAGE_SIZE;

	public PairedConnection(Socket socket, String firstMessage, boolean open, ConnectionDiscover manager, OnNewMessageListener listener) {
		if(listener.messageSize > 128)
			MAX_MESSAGE_SIZE = listener.messageSize;
		else
			MAX_MESSAGE_SIZE = 128;
		this.messageBuffer = new StringBuffer();
		this.manager = manager;
		this.socket = socket;
		this.running = open;
		//		this.messagesToSend = new LinkedList<String>();
		//		this.messagesToSend.add(firstMessage);
		if(open)
			listeningThread();
		sendFirstMessage(firstMessage);
		this.listener = listener;
		listener.getPairedConnection(this);
		if(!open)
			closeConnection();
	}

	public void listeningThread() {


		new Thread(new Runnable() {

			@Override
			public void run() {
				try {

					// Creando los flujos
					input = new InputStreamReader(socket.getInputStream());
					Print.print("Flujo de entrada abierto");

				} catch (Exception e) {
					Print.print("Error al abrir el flujo de entrada");
					running = false;
				}

				while(running) {

					try {
						char[] buf = new char[MAX_MESSAGE_SIZE];
						int length = input.read(buf);
						String message = new String(buf, 0, length);

						// Si se trata del primer mensaje se confirma que el protocolo sea el mismo
						if(!readyToUse) {
							String protocol = XmlParser.readByTag(message, P.PROTOCOL_ID, 0);
							readyToUse = protocol.equals(P.PROTOCOL_VERSION);
							running = readyToUse;
							if(readyToUse) {
								Print.print("Protocolo validado");
							} else {
								Print.print("No coinciden las versiones del protocolo");
							}
						}

						// Para los siguientes mensajes
						else {

							messageBuffer.append(message);
							try {
								Print.print("New message -->");
								messageBuffer.delete(0, listener.onNewMessage(messageBuffer.toString()));
							} catch(StringIndexOutOfBoundsException siobe) {}

						}

					} catch (Exception e) {
//						e.printStackTrace();
						Print.print("Exception-listeningThread-PairedConnection");
						running = false;
					}

				}

				Print.print("Fin del hilo para recibir");
				closeConnection();

			}
		}).start();

	}

	public void closeConnection() {
		try {socket.shutdownInput();} catch(Exception e) {}
		try {socket.shutdownOutput();} catch(Exception e) {}
		try {input.close();} catch(Exception e) {}
		try {output.close();} catch(Exception e) {}
		running = false;
		manager.stopPairedConnection();
		Print.print("Closing PairedConnection...");
		listener.onCloseConnection();
	}

	private void sendFirstMessage(final String message) {

		new Thread(new Runnable() {

			@Override
			public void run() {

				// Esperando a que se abran los flujos de entrada
				//				try {Thread.sleep(1000);} catch (InterruptedException e1) {}

				try {

					// Creando los flujos
					output = new OutputStreamWriter(socket.getOutputStream());
					Print.print("Flujo de salida abierto");

					// Enviando el mensaje de saludo
					output.write(message);
					output.flush();
					Print.print("Primer mensaje enviado");

				} catch (Exception e) {
					Print.print("Error al abrir el flujo de salida");
					running = false;
				}
			}
		}).start();

	}

	public boolean sendMessage(final String message) {

		new Thread(new Runnable() {

			@Override
			public void run() {

				try {

					// Enviando el mensaje de saludo
					output.write(message);
					output.flush();

				} catch (Exception e) {
					Print.print("No se pudo enviar el mensaje");
					Print.print(e.getMessage());
					running = false;
				}
			}
		}).start();

		return running;
	}

}
